package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.entity.MenuButtonDO;
import com.ssy.lingxi.member.merchant.entity.MenuDO;
import com.ssy.lingxi.member.merchant.model.vo.platform.request.*;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformButtonDetailVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformMenuDetailVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.PlatformMenuTreeVO;
import com.ssy.lingxi.member.merchant.repository.MenuButtonRepository;
import com.ssy.lingxi.member.merchant.repository.MenuRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.paas.IBasePaasService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMenuService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台后台 - 菜单管理相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2022-04-13
 */
@Service
public class PlatformMenuServiceImpl implements IPlatformMenuService {
    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private MenuRepository menuRepository;

    @Resource
    private MenuButtonRepository menuButtonRepository;

    @Resource
    private IBasePaasService basePaasService;

    /**
     * 查询树形菜单列表
     *
     * @param headers Http头部信息
     * @return 查询结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<List<PlatformMenuTreeVO>> treeMenus(HttpHeaders headers) {
        memberCacheService.needLoginFromManagePlatform(headers);

        //查询业务中台的按钮
        List<MenuDO> menus = menuRepository.findBySource(UserLoginSourceEnum.BUSINESS_WEB.getCode());
        return Wrapper.success(transferToTree(menus));
    }

    /**
     * 查询菜单详情
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<PlatformMenuDetailVO> findMenu(HttpHeaders headers, PlatformMenuIdVO idVO) {
        memberCacheService.needLoginFromManagePlatform(headers);

        MenuDO menu = menuRepository.findById(idVO.getMenuId()).orElse(null);
        if(menu == null || !menu.getSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        PlatformMenuDetailVO detailVO = new PlatformMenuDetailVO();
        detailVO.setTitle(menu.getTitle());
        detailVO.setOrder(menu.getOrder());
        detailVO.setUrl(menu.getUrl());
        detailVO.setDataAuthConfig(menu.getDataAuthConfig());
        detailVO.setButtons(menu.getButtons().stream().map(button -> {
            PlatformButtonDetailVO buttonDetailVO = new PlatformButtonDetailVO();
            buttonDetailVO.setButtonId(button.getId());
            buttonDetailVO.setName(button.getName());
            buttonDetailVO.setCode(button.getCode());
            buttonDetailVO.setRemark(StringUtils.hasLength(button.getRemark()) ? button.getRemark() : "");
            return buttonDetailVO;
        }).collect(Collectors.toList()));

        return Wrapper.success(detailVO);
    }

    /**
     * 新增菜单
     *
     * @param headers Http头部信息
     * @param menuVO  接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> addMenu(HttpHeaders headers, PlatformMenuVO menuVO) {
        memberCacheService.needLoginFromManagePlatform(headers);

        // 同一个菜单下的按钮标识不能重复
        if(!CollectionUtils.isEmpty(menuVO.getButtons()) && menuVO.getButtons().stream().map(PlatformButtonVO::getCode).distinct().count() != menuVO.getButtons().size()) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_BUTTON_CODE_DUPLICATED);
        }

        //菜单Url不能重复
        if(menuRepository.existsByUrlAndSource(menuVO.getUrl().trim(), UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_URL_EXISTS);
        }

        //查找上级菜单
        MenuDO upperMenu = null;
        if(NumberUtil.notNullOrZero(menuVO.getParentId())) {
            upperMenu = menuRepository.findById(menuVO.getParentId()).orElse(null);
            if(upperMenu == null) {
                return Wrapper.fail(ResponseCode.MC_MS_UPPER_MENU_DOES_NOT_EXIST);
            }
        }

        MenuDO menu = new MenuDO();
        menu.setPaasId(0L);
        menu.setParentId(upperMenu == null ? 0L : upperMenu.getId());
        menu.setKey("");
        menu.setCode("");
        menu.setTitle(menuVO.getTitle());
        menu.setUrl(menuVO.getUrl());
        menu.setOrder(menuVO.getOrder());
        menu.setUp(EnableDisableStatus.DISABLE.getCode());
        menu.setDisabled(false);
        menu.setLevel(upperMenu == null ? 1 : upperMenu.getLevel() + 1);
        menu.setRemark("");
        menu.setSource(UserLoginSourceEnum.BUSINESS_WEB.getCode());
        menu.setDataAuthConfig(menuVO.getDataAuthConfig());
        menu.setAttrs(new HashMap<>());
        menu.setButtons(new HashSet<>());
        menuRepository.saveAndFlush(menu);

        if(!CollectionUtils.isEmpty(menuVO.getButtons())) {
            List<MenuButtonDO> buttons = menuVO.getButtons().stream().map(button -> {
                MenuButtonDO buttonDO = new MenuButtonDO();
                buttonDO.setPaasId(0L);
                buttonDO.setParentId(menu.getId());
                buttonDO.setKey("");
                buttonDO.setName(button.getName());
                buttonDO.setUrl("");
                buttonDO.setCode(button.getCode());
                buttonDO.setRemark(StringUtils.hasLength(button.getRemark()) ? button.getRemark() : "");
                buttonDO.setAttrs(new HashMap<>());
                return buttonDO;
            }).collect(Collectors.toList());
            menuButtonRepository.saveAll(buttons);

            menu.setButtons(new HashSet<>(buttons));
            menuRepository.saveAndFlush(menu);
        }

        return Wrapper.success();
    }

    /**
     * 修改菜单
     *
     * @param headers  Http头部信息
     * @param updateVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updateMenu(HttpHeaders headers, PlatformMenuUpdateVO updateVO) {
        memberCacheService.needLoginFromManagePlatform(headers);

        //查找菜单
        MenuDO menu = menuRepository.findById(updateVO.getMenuId()).orElse(null);
        if(menu == null || !menu.getSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        // 同一个菜单下的按钮标识不能重复
        if(!CollectionUtils.isEmpty(updateVO.getButtons()) && updateVO.getButtons().stream().map(PlatformButtonUpdateVO::getCode).distinct().count() != updateVO.getButtons().size()) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_BUTTON_CODE_DUPLICATED);
        }

        //菜单Url不能重复
        if(menuRepository.existsByUrlAndSourceAndIdNot(updateVO.getUrl().trim(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), updateVO.getMenuId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_URL_EXISTS);
        }

        //记录修改之前的菜单数据权限
        Integer oldDataAuthConfig = menu.getDataAuthConfig();

        menu.setTitle(updateVO.getTitle());
        menu.setUrl(updateVO.getUrl());
        menu.setOrder(updateVO.getOrder());
        menu.setDataAuthConfig(updateVO.getDataAuthConfig());

        //为方便处理，将前端传递的Null值设置为默认值
        if(CollectionUtils.isEmpty(updateVO.getButtons())) {
            updateVO.setButtons(new ArrayList<>());
        } else {
            updateVO.getButtons().forEach(b -> {
                if(NumberUtil.isNullOrZero(b.getButtonId())) {
                    b.setButtonId(0L);
                }
            });
        }

        List<MenuButtonDO> buttons = new ArrayList<>(menu.getButtons());

        //删除按钮
        List<MenuButtonDO> deleteButtons = buttons.stream().filter(button -> updateVO.getButtons().stream().noneMatch(b -> b.getButtonId().equals(button.getId()))).collect(Collectors.toList());

        //修改按钮
        List<MenuButtonDO> updateButtons = buttons.stream().filter(button -> updateVO.getButtons().stream().anyMatch(b -> b.getButtonId().equals(button.getId()))).collect(Collectors.toList());
        updateButtons.forEach(updateButton -> updateVO.getButtons().stream().filter(b -> b.getButtonId().equals(updateButton.getId())).findFirst().ifPresent(b -> {
            updateButton.setCode(b.getCode());
            updateButton.setName(b.getName());
            updateButton.setRemark(StringUtils.hasLength(b.getRemark()) ? b.getRemark() : "");
        }));

        //新增按钮
        List<MenuButtonDO> newButtons = updateVO.getButtons().stream().filter(b -> b.getButtonId().equals(0L)).map(b -> {
            MenuButtonDO buttonDO = new MenuButtonDO();
            buttonDO.setPaasId(0L);
            buttonDO.setParentId(menu.getId());
            buttonDO.setKey("");
            buttonDO.setName(b.getName());
            buttonDO.setUrl("");
            buttonDO.setCode(b.getCode());
            buttonDO.setRemark(StringUtils.hasLength(b.getRemark()) ? b.getRemark() : "");
            buttonDO.setAttrs(new HashMap<>());
            return buttonDO;
        }).collect(Collectors.toList());

        //先删除
        menuButtonRepository.deleteAll(deleteButtons);

        //修改的按钮、新增的按钮可以一起保存
        updateButtons.addAll(newButtons);
        menuButtonRepository.saveAll(updateButtons);

        //重新设置菜单关联的按钮，保存菜单
        menu.setButtons(new HashSet<>(updateButtons));
        menuRepository.saveAndFlush(menu);

        //当不可配置数据权限时，删除已有的数据权限
        if(oldDataAuthConfig.equals(EnableDisableStatus.ENABLE.getCode()) && menu.getDataAuthConfig().equals(EnableDisableStatus.DISABLE.getCode())) {
            basePaasService.removeDataAuthAsync(menu.getId(), menu.getUrl(), menu.getSource());
        }

        return Wrapper.success();
    }

    /**
     * 删除菜单
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> deleteMenu(HttpHeaders headers, PlatformMenuIdVO idVO) {
        memberCacheService.needLoginFromManagePlatform(headers);

        //查找菜单
        MenuDO menu = menuRepository.findById(idVO.getMenuId()).orElse(null);
        if(menu == null || !menu.getSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        //删除已有的数据权限
        basePaasService.removeDataAuthAsync(menu.getId(), menu.getUrl(), menu.getSource());

        //删除菜单
        menuRepository.delete(menu);
        return Wrapper.success();
    }

    /**
     * 递归构建权限树形结构
     * @param menus 菜单列表
     * @return 树形结构的权限列表
     */
    @Override
    public List<PlatformMenuTreeVO> transferToTree(List<MenuDO> menus) {
        if(CollectionUtils.isEmpty(menus)) {
            return new ArrayList<>();
        }

        List<PlatformMenuTreeVO> resultList = new ArrayList<>();

        //首先找到第一级菜单，排序(同级菜单再按id排序)
        List<MenuDO> topList = menus.stream().filter(menu -> menu.getParentId().equals(0L)).sorted(Comparator.comparingInt(MenuDO::getOrder).thenComparingLong(MenuDO::getId)).collect(Collectors.toList());
        //循环、递归构建树
        topList.forEach(top -> {
            PlatformMenuTreeVO topVO = new PlatformMenuTreeVO(top.getId(), top.getTitle(), null);
            recurseTree(topVO, top, menus);
            resultList.add(topVO);
        });

        return resultList;
    }

    /**
     * 递归构树形菜单
     * @param topVO 上级菜单VO
     * @param top  上级菜单
     * @param menus 菜单列表
     */
    private void recurseTree(PlatformMenuTreeVO topVO, MenuDO top , List<MenuDO> menus) {
        //查找下级菜单，排序(同级菜单再按id排序)
        List<MenuDO> subList = menus.stream().filter(s -> s.getParentId().equals(top.getId())).sorted(Comparator.comparingInt(MenuDO::getOrder).thenComparingLong(MenuDO::getId)).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(subList)) {
            return;
        }

        for (MenuDO sub : subList) {
            PlatformMenuTreeVO subVO = new PlatformMenuTreeVO(sub.getId(), sub.getTitle(), null);
            topVO.getChildren().add(subVO);
            recurseTree(subVO, sub, menus);
        }
    }
}
